/* 
 * Copyright (C)2008 Vladimir Hozjan vladimir.hozjan@gmail.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */

/**
 * @file  tetris.h
 *
 * Declaration of tetris engine class
 *
 * @author Vladimir Hozjan
 * @date   25.12.2008 
 *
 * @remarks VHOZ [25.12.2008]: file created
 */
#ifndef _tetris_h_
#define _tetris_h_

/////////////////////////////////////////////////////////////////////  LIBRARIES
#include "tetrisFunctor.h"
#include "tetrisInterfaces.h"

/////////////////////////////////////////////////////  FORWARD CLASS DECLARATION
class TetrisBackground;
class TetrisElement;

/////////////////////////////////////////////////////////////  CLASS DECLARATION
/**
 * @class Tetris
 * @brief Tetris engine
 *
 * Tetris engine provides interface for tetris game.
 *
 * @author VHOZ
 *
 * @remarks VHOZ [25.12.2008]: Class created
 */
class Tetris {
public:
  /// Constructor
  Tetris(SystemInterface & aSystemInterface, unsigned short aNumRow = 20, unsigned short aNumColumn = 10);

  /// Destructor
  ~Tetris();

  /// move element left
  void moveLeft();

  /// move element right
  void moveRight();

  /// move element down
  void moveDown();

  /// drop element
  void drop();

  /// rotate element left
  void rotateLeft();

  /// rotate element right
  void rotateRight();

  /// one nextMove cycle
  void nextMove();

  /// set change (position, score and/or level) callback function
  void setPositionChangeCallback(ITetrisFunctor & aChangeMethod);

  /// set change (position, score and/or level) callback function
  void setElementChangeCallback(ITetrisFunctor & aChangeMethod);

  /// get requested delay in ms for nextMove
  unsigned short getDelay() const;

  /// get current level of game
  unsigned short getLevel() const {return mLevel; };

  /// get current score
  double getScore() const {return mScore;};

  /// get number of lines
  unsigned short getNumberOfLines() const {return mNumLines; };

  /// check for end of game
  bool isGameOver() const {return mGameOver; };

  /// get cell of tetris matrix
  unsigned short getCell(unsigned short aRow, unsigned short aColl) const;

  /// get dimension of next element
  unsigned short getDimensionOfNextElement() const;

  /// get cell of next element
  unsigned short getCellOfNextElement(unsigned short aRow, unsigned short aColl) const;

  static const int MAX_ELEMENT_DIMENSION = 4; ///< max dimension of element
  static const int MAX_ELEMENTS = 7;          ///< max number of different elements
protected:
private:
  /// Constructor
  Tetris();

  /// Copy constructor
  Tetris(Tetris const &);

  /// Set start position for next element
  void setStartPositionAndNextElement();

  /// Element is down or stuck
  void elementDown();

  /// Calculate score and level
  void calculateScoreAndLevel(unsigned short aNumLines, unsigned short aElementId);

  /// Position of element changed in tetris game, notify others
  void notifyPositionChange();

  /// Old element came down to the bottom and new element appeared. Score, level and lines are recalculated.
  void notifyElementChange();

  /* Members */
  ITetrisFunctor * mPositionChangeMethod; ///< Callback functor
  ITetrisFunctor * mElementChangeMethod;  ///< Callback functor
  SystemInterface & mSystem;              ///< Interface class for random number implementation

  unsigned short mLevel;                  ///< Current level
  unsigned short mNumLines;               ///< Number of lines solved
  double mScore;                          ///< Overall score
  bool mGameOver;                         ///< Is game over
  bool mError;                            ///< Error occurred

  const int mNumRows;                     ///< Number of rows
  const int mNumCols;                     ///< Number of columns
  int mRow;                               ///< Row position of current element 
  int mColumn;                            ///< Column position of current element

  TetrisElement *mCurrElement;            ///< Current element
  TetrisElement *mNextElement;            ///< Next element
  TetrisBackground *mBackground;          ///< Background
  TetrisElement **mElementList;            ///< List of elements
};

#endif // _tetris_h_
